package designPattern.creation5.factory;

import designPattern.creation5.factory.AbstractFactory.HPFactory;
import designPattern.creation5.factory.AbstractFactory.IAbstractFactory;
import designPattern.creation5.factory.AbstractFactory.LenoveFactory;
import designPattern.creation5.factory.FactoryMethod.Factory;
import designPattern.creation5.factory.FactoryMethod.HPMouseFactory;
import designPattern.creation5.factory.FactoryMethod.LenoveMouseFactory;
import designPattern.creation5.factory.SimleFactory.MouseFactory1;
import designPattern.creation5.factory.SimleFactory.MouseFactory2;
import designPattern.creation5.factory.SimleFactory.MouseFactory3;

public class Program {
    public static void main(String[] args) {

//        test1(); //普通简单工厂
//        test2();//多方法简单工厂
//        test3();//静态方法简单工厂
//        test4();//工厂方法模式
        test5();//抽象工厂模式

    }


    static void test1() {
        System.out.println("================== 普通简单工厂=====================");
        /** 就是建立一个工厂类，对实现了同一接口的一些类进行实例的创建。**/

        MouseFactory1 mouseFactory = new MouseFactory1();
        String mouseInfo1 = mouseFactory.getMouse(0).GetMouseInfo();
        System.out.println(mouseInfo1);        // 输出：惠普品牌鼠标


        String mouseInfo2 = mouseFactory.getMouse(1).GetMouseInfo();
        System.out.println(mouseInfo2);        //输出：联想品牌鼠标

    }


    static void test2() {
        System.out.println("================== 多方法简单工厂=====================");
        /**  对普通工厂方法模式的改进，在普通工厂方法模式中，如果传递的类型出错，则不能正确创建对象，而多个工厂方法模式是提供多个工厂方法，分别创建对象。
         **/
        MouseFactory2 mouseFactory2 = new MouseFactory2();
        String mouseInfo1 = mouseFactory2.GetHPMouse().GetMouseInfo();
        System.out.println(mouseInfo1);        //输出惠普鼠标品牌


        String mouseInfo2 = mouseFactory2.GetLenoveMouse().GetMouseInfo();
        System.out.println(mouseInfo2);        //输出联想鼠标品牌

    }

    static void test3() {
        System.out.println("================== 静态方法简单工厂=====================");
        /** 将上面的多个工厂方法模式里的方法置为静态的，不需要创建实例，直接调用即可。
         **/

        String mouseInfo1 = MouseFactory3.GetHPMouse().GetMouseInfo();
        System.out.println(mouseInfo1);        //输出惠普鼠标品牌


        String mouseInfo2 = MouseFactory3.GetLenoveMouse().GetMouseInfo();
        System.out.println(mouseInfo2);        //输出联想鼠标品牌

    }

    static void test4() {
        System.out.println("================== 工厂方法模式=====================");
        /** 工厂方法模式中我们把生成产品类的时间延迟，就是通过对应的工厂类来生成对应的产品类，
         * 在这里我们就可以实现“开发-封闭”原则，
         * 无论加多少产品类，我们都不用修改原来类中的代码，而是通过增加工厂类来实现。
         * 但是这还是有缺点的，如果添加键盘产品，就需要添加键盘工厂类。
         * 假如我们要实现的产品接口不止一个，也就是有多个产品接口，不同产品接口有对应的产品族。
         * 什么是产品族呢？简单的理解就是，不同厂家的不仅有鼠标，还有键盘，音响，笔记本可以组成一个产品族。
         * 对于这种情况我们可以采用抽象工厂模式。
         **/


        //实例化惠普鼠标工厂
        Factory factory = new HPMouseFactory();
        String mouseInfo1 = factory.GetMouseFactory().GetMouseInfo();
        System.out.println(mouseInfo1);        //输出惠普鼠标品牌


        //实例化联想鼠标工厂
        Factory factory2 = new LenoveMouseFactory();
        String mouseInfo2 = factory2.GetMouseFactory().GetMouseInfo();
        System.out.println(mouseInfo2);        //输出联想鼠标品牌


//

    }

    static void test5() {
        System.out.println("================== 抽象工厂模式=====================");
        /** 抽象工厂模式中我们可以定义实现不止一个接口，一个工厂也可以生成不止一个产品类，抽象工厂模式较好的实现了“开放-封闭”原则，是三个模式中较为抽象，并具一般性的模式。我们在使用中要注意使用抽象工厂模式的条件。
         无论是工厂模式增加代码复制度，有没有一种办法，不需要创建工厂，也能解决代码以后变动修改少方法。答案是有的，通过（ioc）控制反转，对象在被创建的时候，由一个调控系统内所有对象的外界实体，将其所依赖的对象的引用传递给它。也可以说，(di)依赖被注入到对象中。
         后续继续讲解如何使ioc优化程序。
         **/


        //实例化惠普鼠标工厂
        IAbstractFactory factory = new HPFactory();
        String mouseInfo1 = factory.GetMouseFactory().GetMouseInfo();
        String keyboard1 = factory.GetKeyboardFactory().GetKeyboardInfo();
        System.out.println(mouseInfo1);//输出惠普鼠标品牌
        System.out.println(keyboard1);//输出惠普键盘


        //实例化联想鼠标工厂
        IAbstractFactory factory2 = new LenoveFactory();
        String mouseInfo2 = factory2.GetMouseFactory().GetMouseInfo();
        String keyboard2 = factory2.GetKeyboardFactory().GetKeyboardInfo();
        System.out.println(mouseInfo2);//输出联想鼠标品牌
        System.out.println(keyboard2); //输出联想键盘品牌
    }


}
